package cn.com.doone.common.uc.utils;

import static cn.com.doone.common.uc.domain.oauth.Constants.OAUTH_LOGIN_VIEW;
import static cn.com.doone.common.uc.domain.oauth.Constants.REQUEST_USERNAME;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;

import cn.com.doone.common.uc.infrastructure.DateUtils;
import cn.com.doone.common.uc.web.WebUtils;

public class RedisUtils {

	// redis中命名空间前缀
	private static final String PREFIX = "cn:com:doone:";

	// redis中IP黑名单的空间
	private static final String IP_BLACK_SPACE = PREFIX + "ipBlack";

	//redis中ip白名单的空间
//	private static final String IP_WHITE_SPACE = PREFIX + "ipWhite";
	
	// redis中ip的命名空间
	private static final String IPSPACE = PREFIX + "ipSpace:";

	// redis中账号的命名空间
	private static final String ACCOUNTSPACE = PREFIX + "accountSpace:";

	//验证IP规则
	private static List<Map<String, Object>> ipDateList;
	static {
		ipDateList = new ArrayList<Map<String, Object>>();
		Map<String, Object> map = new HashMap<String, Object>();
//		map.put("calendarType", Calendar.DATE);
//		map.put("day", -1);
//		map.put("count", 45);
//		map.put("unLockDay", 1);
//		ipDateList.add(map);
//		map = new HashMap<String, Object>();
//		map.put("calendarType", Calendar.HOUR);
//		map.put("day", -1);
//		map.put("count", 30);
//		map.put("unLockDay", 0.5);
//		ipDateList.add(map);
		map.put("calendarType", Calendar.MINUTE);
		map.put("day", -5);
		map.put("count", 30);
		map.put("unLockDay", 5);
		ipDateList.add(map);
	}
	
	//验证账号规则
	private static List<Map<String,Object>> accountDateList;
	static {
		accountDateList = new ArrayList<Map<String, Object>>();
		Map<String, Object> map = new HashMap<String, Object>();
//		map.put("calendarType", Calendar.DATE);
//		map.put("day", -1);
//		map.put("count", 15);
//		map.put("unLockDay", 3);
//		accountDateList.add(map);
//		map = new HashMap<String, Object>();
//		map.put("calendarType", Calendar.HOUR);
//		map.put("day", -1);
//		map.put("count", 10);
//		map.put("unLockDay", 2);
//		accountDateList.add(map);
		map.put("calendarType", Calendar.MINUTE);
		map.put("day", -5);
		map.put("count", 5);
		map.put("unLockDay", 5);
		accountDateList.add(map);
	}

	/**
	 * 初始化redisTemplate
	 * 
	 * @return
	 */
	@SuppressWarnings({ "resource", "unchecked" })
	public static final RedisTemplate<String, Object> getRedisTemplate() {
		ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis.xml");
		return appCtx.getBean("redisTemplate", RedisTemplate.class);
	}
	
	/**
	 * 验证IP是否在黑名单及是否被锁定
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public static boolean validIp(HttpServletRequest request, HttpServletResponse response) throws Exception {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		String ip = WebUtils.retrieveClientIp(request);
		
		//验证是否在白名单中
//		SetOperations<String,Object> whiteSet = redisTemplate.opsForSet();
//		if(whiteSet.isMember(IP_WHITE_SPACE, ip)) {
//			return false;
//		}
		
		// 从ip黑名单中查看有没有数据
//		SetOperations<String, Object> set = redisTemplate.opsForSet();
//		if (set.isMember(IP_BLACK_SPACE, ip)) {
//			request.setAttribute("username", request.getParameter(REQUEST_USERNAME));
//			request.setAttribute("oauth_login_error", true);
//			request.setAttribute("oauth_login_error_message", "您的IP已被列入黑名单，请联系系统管理员。");
//			request.getRequestDispatcher(OAUTH_LOGIN_VIEW).forward(request, response);
//			return true;
//		}
		// 查询是否有被锁定
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long lockCount = list.size(IPSPACE + ip);
		if (lockCount == 0) {
			return false;
		}
//		if(lockCount >= 60) {
//			request.setAttribute("username", request.getParameter(REQUEST_USERNAME));
//			request.setAttribute("oauth_login_error", true);
//			request.setAttribute("oauth_login_error_message", "您的IP已被列入黑名单，请联系系统管理员。");
//			request.getRequestDispatcher(OAUTH_LOGIN_VIEW).forward(request, response);
//			return true;
//		}
		// 最后录入的数据
		Date lastFailTime = (Date) list.index(IPSPACE + ip, 0);
		Date currentTime = new Date();
		for (Map<String, Object> dateMap : ipDateList) {
			int calendarType = Integer.parseInt(dateMap.get("calendarType").toString());
			int day = Integer.parseInt(dateMap.get("day").toString());
			int count = Integer.parseInt(dateMap.get("count").toString());
			int unLockDay = Integer.parseInt(dateMap.get("unLockDay").toString());
			for (int i = 0; i < lockCount; i++) {
				Date countDate = DateUtils.dayAddAndSub(lastFailTime, calendarType, day);
				Date failDate = (Date) list.index(IPSPACE + ip, i);
				if (countDate.before(failDate)) {
					if (i >= count) {
						Date unLockTime = DateUtils.dayAddAndSub(lastFailTime, calendarType, unLockDay);
						if(currentTime.before(unLockTime)) {
							RedisUtils.addIpList(request);
							request.setAttribute("username", request.getParameter(REQUEST_USERNAME));
							request.setAttribute("oauth_login_error", true);
							request.setAttribute("oauth_login_error_message",
									"您的IP将于" + DateUtils.toDateTime(unLockTime) + "后解锁，请稍后再试。");
							request.getRequestDispatcher(OAUTH_LOGIN_VIEW).forward(request, response);
							return true;
						}
					}
				}
			}
		}

		return false;
	}

	/**
	 * 验证IP是否在黑名单及是否被锁定
	 * @param request
	 * @param paramsMap
	 */
	public static void validIp(HttpServletRequest request, Map<String, Object> paramsMap) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		String ip = WebUtils.retrieveClientIp(request);
		// 从ip黑名单中查看有没有数据
//		SetOperations<String, Object> set = redisTemplate.opsForSet();
//		if (set.isMember(IP_BLACK_SPACE, ip)) {
//			paramsMap.put("success", false);
//			paramsMap.put("message", "您的IP已被永久锁定，如需解锁请联系系统管理员。");
//			return;
//		}
		// 查询是否有被锁定
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long lockCount = list.size(IPSPACE + ip);
		if (lockCount == 0) {
			return;
		}
//		if(lockCount >= 60) {
//			RedisUtils.addIpBlack(ip);
//			paramsMap.put("success", false);
//			paramsMap.put("message", "您的IP已被永久锁定，如需解锁请联系系统管理员。");
//			return;
//		}
		// 最后录入的数据
		Date lastFailTime = (Date) list.index(IPSPACE + ip, 0);
		Date currentTime = new Date();
		for (Map<String, Object> dateMap : ipDateList) {
			int calendarType = Integer.parseInt(dateMap.get("calendarType").toString());
			int day = Integer.parseInt(dateMap.get("day").toString());
			int count = Integer.parseInt(dateMap.get("count").toString());
			int unLockDay = Integer.parseInt(dateMap.get("unLockDay").toString());
			for (int i = 0; i < lockCount; i++) {
				Date countDate = DateUtils.dayAddAndSub(lastFailTime, calendarType, day);
				Date failDate = (Date) list.index(IPSPACE + ip, i);
				if (countDate.before(failDate)) {
					if (i >= count) {
						Date unLockTime = DateUtils.dayAddAndSub(lastFailTime, calendarType, unLockDay);
						if(currentTime.before(unLockTime)) {
							paramsMap.put("success", false);
							paramsMap.put("message", "您的IP将于" + DateUtils.toDateTime(unLockTime) + "后解锁，请稍后再试。");
							return;
						}
					}
				}
			}
		}
	}

	/**
	 * 验证账号是否被锁
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public static boolean validAccount(HttpServletRequest request, HttpServletResponse response) throws Exception{
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		String account = request.getParameter(REQUEST_USERNAME);
		// 查询是否有被锁定
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long lockCount = list.size(ACCOUNTSPACE + account);
		if (lockCount == 0) {
			return false;
		}
		// 最后录入的数据
		Date lastFailTime = (Date) list.index(ACCOUNTSPACE + account, 0);
		Date currentTime = new Date();
		for (Map<String, Object> dateMap : accountDateList) {
			int calendarType = Integer.parseInt(dateMap.get("calendarType").toString());
			int day = Integer.parseInt(dateMap.get("day").toString());
			int count = Integer.parseInt(dateMap.get("count").toString());
			int unLockDay = Integer.parseInt(dateMap.get("unLockDay").toString());
			for (int i = 0; i < lockCount; i++) {
				Date countDate = DateUtils.dayAddAndSub(lastFailTime, calendarType, day);
				Date failDate = (Date) list.index(ACCOUNTSPACE + account, i);
				if (countDate.before(failDate)) {
					if (i >= count) {
						Date unLockTime = DateUtils.dayAddAndSub(lastFailTime, calendarType, unLockDay);
						if(currentTime.before(unLockTime)) {
							RedisUtils.addAccountList(account);
							RedisUtils.addIpList(request);
							request.setAttribute("username", request.getParameter(REQUEST_USERNAME));
							request.setAttribute("oauth_login_error", true);
							request.setAttribute("oauth_login_error_message",
									"由于您的账号尝试登录的次数过多，现已被锁定,将于" + DateUtils.toDateTime(unLockTime) + "后解锁，请稍后再试。");
							request.getRequestDispatcher(OAUTH_LOGIN_VIEW).forward(request, response);
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	
	/**
	 * 验证账号是否被锁
	 * @param request
	 * @param paramsMap
	 */
	public static void validAccount(String account,Map<String, Object> paramsMap) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		// 查询是否有被锁定
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long lockCount = list.size(ACCOUNTSPACE + account);
		if (lockCount == 0) {
			return;
		}
		// 最后录入的数据
		Date lastFailTime = (Date) list.index(ACCOUNTSPACE + account, 0);
		Date currentTime = new Date();
		for (Map<String, Object> dateMap : accountDateList) {
			int calendarType = Integer.parseInt(dateMap.get("calendarType").toString());
			int day = Integer.parseInt(dateMap.get("day").toString());
			int count = Integer.parseInt(dateMap.get("count").toString());
			int unLockDay = Integer.parseInt(dateMap.get("unLockDay").toString());
			for (int i = 0; i < lockCount; i++) {
				Date countDate = DateUtils.dayAddAndSub(lastFailTime, calendarType, day);
				Date failDate = (Date) list.index(ACCOUNTSPACE + account, i);
				if (countDate.before(failDate)) {
					if (i >= count) {
						Date unLockTime = DateUtils.dayAddAndSub(lastFailTime, calendarType, unLockDay);
						if(currentTime.before(unLockTime)) {
							paramsMap.put("success", false);
							paramsMap.put("message", "由于您的账号尝试登录的次数过多，现已被锁定,将于" + DateUtils.toDateTime(unLockTime) + "后解锁，请稍后再试。");
							return;
						}
					}
				}
			}
		}
	}

	/**
	 * 添加ip数据
	 * 
	 * @param ip
	 */
	public static void addIpList(HttpServletRequest request) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		String ip = WebUtils.retrieveClientIp(request);
		ListOperations<String, Object> list = redisTemplate.opsForList();
		list.rightPush(IPSPACE + ip, new Date());
	}
	
	/**
	 * 添加ip黑名单
	 * @param ip
	 */
	public static void addIpBlack(String ip) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		SetOperations<String, Object> set = redisTemplate.opsForSet();
		set.add(IP_BLACK_SPACE, ip);
	}
	
	/**
	 * 添加账号数据
	 * @param username
	 */
	public static void addAccountList(String username) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		ListOperations<String, Object> list = redisTemplate.opsForList();
		list.rightPush(ACCOUNTSPACE + username, new Date());
	}
	
	/**
	 * 删除账号数据
	 * @param username
	 */
	public static void delAccountList(String username) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long size = list.size(ACCOUNTSPACE + username);
		for(int i=0;i<size;i++) {
			list.rightPop(ACCOUNTSPACE + username);
		}
	}
	/**
	 * 删除ip锁定
	 * @param ip
	 */
	public static void delIp(String ip) {
		RedisTemplate<String, Object> redisTemplate = RedisUtils.getRedisTemplate();
		ListOperations<String, Object> list = redisTemplate.opsForList();
		long size = list.size(IPSPACE + ip);
		for(int i=0;i<size;i++) {
			list.rightPop(IPSPACE + ip);
		}
		SetOperations<String, Object> set = redisTemplate.opsForSet();
		set.remove(IP_BLACK_SPACE, ip);
	}
}
